﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CoreUtils.WIL
{
    /// <summary>
    /// Edge detection functions from WIL library
    /// </summary>
    public class Edge
    {
        public enum D64 : int
        {
            SobelParam = 0,
            CorrParam = 1
        };

        public enum I32 : int
        {
            SobelParam = 0,
            CorrParam = 1
        };

        public static FVIL.Data.CFviImage arcEdge(FVIL.Data.CFviImage src, int detectMode,
            double centerX, double centerY, double radius, double angleSt, double angleEd,
            int minThreshold)
        {
            FVIL.Edge.CFviArcEdge parser = new FVIL.Edge.CFviArcEdge();
            if (FVIL.ErrorCode._SUCCESS != FVIL.Edge.CFviArcEdge.CheckValidity(src))
                return null;
            parser.SrcImages[0] = src;
            parser.Center = new FVIL.Data.CFviPoint(centerX, centerY);
            parser.Radius = radius;
            parser.AngleSt = new FVIL.Data.CFviAngle(angleSt);
            parser.AngleEd = new FVIL.Data.CFviAngle(angleEd);
            parser.MinThreshold = minThreshold;
            parser.DetectMode = (FVIL.Edge.DetectMode)detectMode;
            parser.Execute();
            FVIL.Data.CFviImage dst = new FVIL.Data.CFviImage();
            {
                FVIL.GDI.CFviDisplay display = new FVIL.GDI.CFviDisplay();
                display.Image = src;
                display.DisplayRect = src.Window;
                FVIL.GDI.CFviOverlay pOverlay0 = new FVIL.GDI.CFviOverlay();
                pOverlay0.Scaling = true;
                display.Overlays.Add(pOverlay0);
                {
                    FVIL.Data.CFviLineSegment ls = new FVIL.Data.CFviLineSegment();
                    FVIL.GDI.CFviGdiPoint center = new FVIL.GDI.CFviGdiPoint(parser.Center);
                    center.Size = new System.Drawing.Size(3, 3);
                    center.Style = FVIL.GDI.FigureStyle.Cross;
                    center.Pen.Color = System.Drawing.Color.FromArgb(0, 0, 255);
                    FVIL.GDI.CFviGdiCircle arc = new FVIL.GDI.CFviGdiCircle(new FVIL.Data.CFviCircle(parser.Center, parser.Radius));
                    arc.Pen.Color = System.Drawing.Color.FromArgb(255, 255, 0);
                    ls.St = parser.Center;
                    ls.Ed = new FVIL.Data.CFviPoint(ls.St.X + parser.Radius, ls.St.Y);
                    FVIL.GDI.CFviGdiLineSegment st = new FVIL.GDI.CFviGdiLineSegment(ls);
                    st.Pen.Color = System.Drawing.Color.FromArgb(0, 255, 0);
                    st.Pen.Style = FVIL.GDI.PenStyle.Dot;
                    st.Angle = parser.AngleSt;

                    ls.St = parser.Center;
                    ls.Ed = new FVIL.Data.CFviPoint(ls.St.X + parser.Radius, ls.St.Y);
                    FVIL.GDI.CFviGdiLineSegment ed = new FVIL.GDI.CFviGdiLineSegment(ls);
                    ed.Pen.Color = System.Drawing.Color.FromArgb(0, 255, 0);
                    ed.Angle = parser.AngleEd;

                    pOverlay0.Figures.Add(center);
                    pOverlay0.Figures.Add(arc);
                    pOverlay0.Figures.Add(st);
                    pOverlay0.Figures.Add(ed);
                }
                for (int i = 0; i < (parser.Result.Count); i++)
                {
                    FVIL.Edge.CFviEdgeData edge = parser.Result[i];
                    FVIL.GDI.CFviGdiPoint position = new FVIL.GDI.CFviGdiPoint(edge.Position);
                    position.Size = new System.Drawing.Size(3, 3);
                    position.Style = FVIL.GDI.FigureStyle.Cross;
                    position.Pen.Color = System.Drawing.Color.FromArgb(255, 0, 0);

                    pOverlay0.Figures.Add(position);
                }

                display.SaveImage(dst, display.DisplayRect, 1.0);
            }
            return dst;
        }

        public static FVIL.Data.CFviImage boxEdge(FVIL.Data.CFviImage src, int scanDirection,
            int edgeDirection, double rectStX, double rectStY, double rectEdX, double rectEdY,
            int number, int lineWidth, int threshold, int foot, int len)
        {
            FVIL.Edge.CFviBoxEdge parser = new FVIL.Edge.CFviBoxEdge();
            if (FVIL.ErrorCode._SUCCESS != FVIL.Edge.CFviBoxEdge.CheckValidity(src))
                return null;
            parser.SrcImages[0] = src;
            parser.Box = new FVIL.Data.CFviRectangle(rectStX, rectStY, rectEdX, rectEdY);
            parser.Number = number;
            parser.LineWidth = lineWidth;
            parser.Threshold = threshold;
            parser.ScanDirection = (FVIL.ScanDirection)scanDirection;
            parser.EdgeDirection = (FVIL.Edge.Direction)edgeDirection;
            parser.Foot = foot;
            parser.Len = len;
            parser.Execute();
            FVIL.Data.CFviImage dst = new FVIL.Data.CFviImage();
            {
                FVIL.GDI.CFviDisplay display = new FVIL.GDI.CFviDisplay();
                display.Image = src;
                display.DisplayRect = src.Window;

                FVIL.GDI.CFviOverlay pOverlay0 = new FVIL.GDI.CFviOverlay();
                pOverlay0.Scaling = true;
                display.Overlays.Add(pOverlay0);

                {
                    FVIL.GDI.CFviGdiRectangle rect = new FVIL.GDI.CFviGdiRectangle(parser.Box);
                    rect.Ed = new FVIL.Data.CFviPoint(rect.Ed.X + 1, rect.Ed.Y + 1);
                    rect.Pen.Color = System.Drawing.Color.FromArgb(0, 0, 255);
                    double width = (parser.Box.Width + 1) / parser.Number;

                    List<FVIL.GDI.CFviGdiLineSegment> lines = new List<FVIL.GDI.CFviGdiLineSegment>();
                    for (int i = 0; i <= parser.Number; i++)
                    {
                        FVIL.GDI.CFviGdiLineSegment ls = new FVIL.GDI.CFviGdiLineSegment();
                        ls.St = new FVIL.Data.CFviPoint(parser.Box.St.X + width * i, parser.Box.St.Y + 1);
                        ls.Ed = new FVIL.Data.CFviPoint(parser.Box.St.X + width * i, parser.Box.Ed.Y + 1);
                        ls.Pen.Color = System.Drawing.Color.FromArgb(255, 255, 0);
                        lines.Add(ls);
                    }

                    pOverlay0.Figures.Add(rect);
                    for (int i = 0; i < lines.Count; i++)
                        pOverlay0.Figures.Add(lines[i]);
                }

                for (int i = 0; i < (parser.Result.Count); i++)
                {
                    FVIL.Edge.CFviEdgeData edge = parser.Result[i];
                    FVIL.GDI.CFviGdiPoint position = new FVIL.GDI.CFviGdiPoint(edge.Position);
                    position.Size = new System.Drawing.Size(3, 3);
                    position.Style = FVIL.GDI.FigureStyle.Cross;
                    position.Pen.Color = System.Drawing.Color.FromArgb(255, 0, 0);    // 赤.

                    pOverlay0.Figures.Add(position);
                }
                display.SaveImage(dst, display.DisplayRect, 1.0);
            }
            return dst;
        }

        public static FVIL.Data.CFviImage correlationEdge(FVIL.Data.CFviImage src, int borderMode,
            int magMode, int saveMode, int regionW, int regionH, double sigmoid, double varThreshold,
            int edgeThreshold, int nmsLength)
        {
            FVIL.Edge.CFviEdge2DCorrelation parser = new FVIL.Edge.CFviEdge2DCorrelation();
            FVIL.Data.CFviImage dst = new FVIL.Data.CFviImage();
            int valid = FVIL.Edge.CFviEdge2DCorrelation.CheckValidity(src);
            if (valid != FVIL.ErrorCode._SUCCESS)
                throw new FVIL.CFviException(valid, "FVIL.Edge.CFviEdge2DCorrelation.CheckValidity");
            parser.SrcImages[0] = src;
            parser.DstImages[0] = dst;
            if (!parser.IsValid())
                parser.Validate();

            parser.BorderMode = (FVIL.BorderMode)borderMode;
            parser.MagMode = (FVIL.Edge.MagMode)magMode;
            parser.SaveMode = (FVIL.Edge.SaveMode)saveMode;

            parser.Param.RegionWidth = regionW;
            parser.Param.RegionHeight = regionH;
            parser.Param.SigmoidK = sigmoid;
            parser.Param.VarThreshold = varThreshold;
            parser.Param.EdgeThreshold = edgeThreshold;
            parser.Param.NmsLength = nmsLength;
            parser.Execute();
            return dst;
        }

        public static FVIL.Data.CFviImage sobelEdge(FVIL.Data.CFviImage src, int borderMode,
            int magMode, int saveMode, int edgeThreshold, int nmsLength)
        {
            FVIL.Edge.CFviEdge2DSobel parser = new FVIL.Edge.CFviEdge2DSobel();
            FVIL.Data.CFviImage dst = new FVIL.Data.CFviImage();
            int valid = FVIL.Edge.CFviEdge2DSobel.CheckValidity(src);
            if (valid != FVIL.ErrorCode._SUCCESS)
                throw new FVIL.CFviException(valid, "FVIL.Edge.CFviEdge2DSobel.CheckValidity");
            parser.SrcImages[0] = src;
            parser.DstImages[0] = dst;
            if (!parser.IsValid())
                parser.Validate();
            parser.BorderMode = (FVIL.BorderMode)borderMode;
            parser.MagMode = (FVIL.Edge.MagMode)magMode;
            parser.SaveMode = (FVIL.Edge.SaveMode)saveMode;
            parser.Param.EdgeThreshold = edgeThreshold;
            parser.Param.NmsLength = nmsLength;
            parser.Execute();
            return dst;
        }

        public static FVIL.Data.CFviImage edge2DEdgeResultD64(FVIL.Data.CFviImage src,
            FVIL.Data.CFviDataObject param, int borderMode, int magMode, int saveMode)
        {
            FVIL.Edge.CFviEdge2D parser = new FVIL.Edge.CFviEdge2D();
            FVIL.Edge.CFviEdgeResultD64 result = new FVIL.Edge.CFviEdgeResultD64();
            FVIL.Data.CFviImage dst = new FVIL.Data.CFviImage();
            int valid = FVIL.Edge.CFviEdge2D.CheckValidity(src);
            if (valid != FVIL.ErrorCode._SUCCESS)
                throw new FVIL.CFviException(valid, "FVIL.Edge.CFviEdge2D.CheckValidity");
            parser.SrcImages[0] = src;
            parser.DstImages[0] = dst;
            if (!parser.IsValid())
                parser.Validate();
            parser.Result = result;
            parser.BorderMode = (FVIL.BorderMode)borderMode;
            parser.MagMode = (FVIL.Edge.MagMode)magMode;
            parser.SaveMode = (FVIL.Edge.SaveMode)saveMode;
            parser.Param = param;
            parser.Execute();
            return dst;
        }

        public static FVIL.Data.CFviImage edge2DEdgeResultD64SobelParam(FVIL.Data.CFviImage src,
            int borderMode, int magMode, int saveMode)
        {
            FVIL.Edge.CFviEdge2DSobelParam param = new FVIL.Edge.CFviEdge2DSobelParam();
            param.EdgeThreshold = 120;
            param.NmsLength = 1;

            return edge2DEdgeResultD64(src, param, borderMode, magMode, saveMode);
        }

        public static FVIL.Data.CFviImage edge2DEdgeResultD64CorrelationParam(FVIL.Data.CFviImage src,
            int borderMode, int magMode, int saveMode)
        {
            FVIL.Edge.CFviEdge2DCorrelationParam param = new FVIL.Edge.CFviEdge2DCorrelationParam();
            param.RegionWidth = 13;
            param.RegionHeight = 5;
            param.SigmoidK = 1.0;
            param.VarThreshold = 20.0;
            param.EdgeThreshold = 40;
            param.NmsLength = 6;

            return edge2DEdgeResultD64(src, param, borderMode, magMode, saveMode);
        }

        public static FVIL.Data.CFviImage edge2DEdgeResultI32(FVIL.Data.CFviImage src,
            FVIL.Data.CFviDataObject param, int borderMode, int magMode, int saveMode)
        {
            FVIL.Edge.CFviEdge2D parser = new FVIL.Edge.CFviEdge2D();
            FVIL.Edge.CFviEdgeResultI32 result = new FVIL.Edge.CFviEdgeResultI32();
            FVIL.Data.CFviImage dst = new FVIL.Data.CFviImage();
            int valid = FVIL.Edge.CFviEdge2D.CheckValidity(src);
            if (valid != FVIL.ErrorCode._SUCCESS)
                throw new FVIL.CFviException(valid, "FVIL.Edge.CFviEdge2D.CheckValidity");
            parser.SrcImages[0] = src;
            parser.DstImages[0] = dst;
            if (!parser.IsValid())
                parser.Validate();
            parser.Result = result;
            parser.BorderMode = (FVIL.BorderMode)borderMode;
            parser.MagMode = (FVIL.Edge.MagMode)magMode;
            parser.SaveMode = (FVIL.Edge.SaveMode)saveMode;
            parser.Param = param;
            parser.Execute();
            return dst;
        }

        public static FVIL.Data.CFviImage edge2DEdgeResultI32SobelParam(FVIL.Data.CFviImage src,
            int borderMode, int magMode, int saveMode)
        {
            FVIL.Edge.CFviEdge2DSobelParam param = new FVIL.Edge.CFviEdge2DSobelParam();
            param.EdgeThreshold = 120;
            param.NmsLength = 1;

            return edge2DEdgeResultI32(src, param, borderMode, magMode, saveMode);
        }

        public static FVIL.Data.CFviImage edge2DEdgeResultI32CorrelationParam(FVIL.Data.CFviImage src,
            int borderMode, int magMode, int saveMode)
        {
            FVIL.Edge.CFviEdge2DCorrelationParam param = new FVIL.Edge.CFviEdge2DCorrelationParam();
            param.RegionWidth = 13;
            param.RegionHeight = 5;
            param.SigmoidK = 1.0;
            param.VarThreshold = 20.0;
            param.EdgeThreshold = 40;
            param.NmsLength = 6;

            return edge2DEdgeResultI32(src, param, borderMode, magMode, saveMode);
        }

        public static FVIL.Data.CFviImage lineEdge(FVIL.Data.CFviImage src, double stX, double stY,
            double edX, double edY, int lineW, int threshold, int minusFoot, int plusFoot,
            int minusLen, int plusLen)
        {
            FVIL.Edge.CFviLineEdge parser = new FVIL.Edge.CFviLineEdge();
            if (FVIL.ErrorCode._SUCCESS != FVIL.Edge.CFviLineEdge.CheckValidity(src))
                return null;
            parser.SrcImages[0] = src;
            parser.ScanLine = new FVIL.Data.CFviLineSegment(stX, stY, edX, edY);
            parser.LineWidth = lineW;
            parser.Threshold = threshold;

            FVIL.Edge.CFviEdgeFilter filter = parser.Filter;
            filter.minus_foot = minusFoot;
            filter.plus_foot = plusFoot;
            filter.minus_len = minusLen;
            filter.plus_len = plusLen;
            parser.Execute();
            FVIL.Data.CFviImage dst = new FVIL.Data.CFviImage();
            {
                FVIL.GDI.CFviDisplay display = new FVIL.GDI.CFviDisplay();
                display.Image = src;
                display.DisplayRect = src.Window;

                FVIL.GDI.CFviOverlay pOverlay0 = new FVIL.GDI.CFviOverlay();
                pOverlay0.Scaling = true;
                display.Overlays.Add(pOverlay0);

                {
                    FVIL.GDI.CFviGdiLineSegment ls = new FVIL.GDI.CFviGdiLineSegment(parser.ScanLine);
                    ls.Pen.Color = System.Drawing.Color.FromArgb(255, 255, 0);    // 黄.
                    pOverlay0.Figures.Add(ls);
                }

                for (int i = 0; i < (parser.Result.Count); i++)
                {
                    FVIL.Edge.CFviEdgeData edge = parser.Result[i];
                    FVIL.GDI.CFviGdiPoint position = new FVIL.GDI.CFviGdiPoint(edge.Position);
                    position.Size = new System.Drawing.Size(3, 3);
                    position.Style = FVIL.GDI.FigureStyle.Cross;
                    position.Pen.Color = System.Drawing.Color.FromArgb(255, 0, 0);
                    pOverlay0.Figures.Add(position);
                }
                display.SaveImage(dst, display.DisplayRect, 1.0);
            }
            return dst;
        }

        public static FVIL.Data.CFviImage pairEdge(FVIL.Data.CFviImage src, int colorMode,
            double stX, double stY, double angle, int width, int threshold)
        {
            FVIL.Edge.CFviPairEdge parser = new FVIL.Edge.CFviPairEdge();
            if (FVIL.ErrorCode._SUCCESS != FVIL.Edge.CFviPairEdge.CheckValidity(src))
                return null;
            parser.SrcImages[0] = src;
            parser.Position = new FVIL.Data.CFviPoint(stX, stY);
            parser.Angle = new FVIL.Data.CFviAngle(angle);
            parser.Width = width;
            parser.Threshold = threshold;
            parser.Color = (FVIL.Edge.ObjectColor)colorMode;
            parser.Execute();
            FVIL.Data.CFviImage dst = new FVIL.Data.CFviImage();
            {
                FVIL.GDI.CFviDisplay display = new FVIL.GDI.CFviDisplay();
                display.Image = src;
                display.DisplayRect = src.Window;

                FVIL.GDI.CFviOverlay pOverlay0 = new FVIL.GDI.CFviOverlay();
                pOverlay0.Scaling = true;
                display.Overlays.Add(pOverlay0);

                {
                    FVIL.Data.CFviLineSegment _ls = new FVIL.Data.CFviLineSegment();
                    _ls.St = new FVIL.Data.CFviPoint(parser.Position.X - 50, parser.Position.Y);
                    _ls.St = FVIL.Math.Rotate(_ls.St, parser.Position, parser.Angle);
                    _ls.Ed = new FVIL.Data.CFviPoint(parser.Position.X + 50, parser.Position.Y);
                    _ls.Ed = FVIL.Math.Rotate(_ls.Ed, parser.Position, parser.Angle);

                    FVIL.Data.CFviLine _line = _ls.ToCFviLine();

                    FVIL.GDI.CFviGdiPoint center = new FVIL.GDI.CFviGdiPoint(parser.Position);
                    center.Size = new System.Drawing.Size(3, 3);
                    center.Style = FVIL.GDI.FigureStyle.Cross;
                    center.Pen.Color = System.Drawing.Color.FromArgb(0, 0, 255);

                    FVIL.GDI.CFviGdiLine line = new FVIL.GDI.CFviGdiLine(_line);
                    line.Pen.Color = System.Drawing.Color.FromArgb(255, 255, 0);

                    pOverlay0.Figures.Add(center);
                    pOverlay0.Figures.Add(line);
                }

                for (int i = 0; i < (parser.Result.Count); i++)
                {
                    FVIL.Edge.CFviEdgeData edge = parser.Result[i];
                    FVIL.GDI.CFviGdiPoint position = new FVIL.GDI.CFviGdiPoint(edge.Position);
                    position.Size = new System.Drawing.Size(3, 3);
                    position.Style = FVIL.GDI.FigureStyle.Cross;
                    position.Pen.Color = System.Drawing.Color.FromArgb(255, 0, 0);

                    pOverlay0.Figures.Add(position);
                }

                display.SaveImage(dst, display.DisplayRect, 1.0);
            }
            return dst;
        }

        public static FVIL.Data.CFviImage radialEdge(FVIL.Data.CFviImage src, int scanDirection,
            double centerX, double centerY, double radius, int number, int threshold)
        {
            FVIL.Edge.CFviRadialEdge parser = new FVIL.Edge.CFviRadialEdge();
            if (FVIL.ErrorCode._SUCCESS != FVIL.Edge.CFviRadialEdge.CheckValidity(src))
                return null;
            parser.SrcImages[0] = src;
            parser.Radial = new FVIL.Data.CFviCircle(centerX, centerY, radius);
            parser.Number = number;
            parser.Threshold = threshold;
            parser.ScanDirection = (FVIL.Edge.ScanDirection)scanDirection;
            parser.Execute();
            FVIL.Data.CFviImage dst = new FVIL.Data.CFviImage();
            {
                FVIL.GDI.CFviDisplay display = new FVIL.GDI.CFviDisplay();
                display.Image = src;
                display.DisplayRect = src.Window;

                FVIL.GDI.CFviOverlay pOverlay0 = new FVIL.GDI.CFviOverlay();
                pOverlay0.Scaling = true;
                display.Overlays.Add(pOverlay0);

                {
                    FVIL.GDI.CFviGdiPoint center = new FVIL.GDI.CFviGdiPoint(parser.Radial.Center);
                    center.Size = new System.Drawing.Size(3, 3);
                    center.Style = FVIL.GDI.FigureStyle.Cross;
                    center.Pen.Color = System.Drawing.Color.FromArgb(0, 0, 255);

                    FVIL.GDI.CFviGdiCircle circle = new FVIL.GDI.CFviGdiCircle(parser.Radial);
                    circle.Pen.Color = System.Drawing.Color.FromArgb(0, 0, 255);

                    List<FVIL.GDI.CFviGdiLineSegment> lines = new List<FVIL.GDI.CFviGdiLineSegment>();
                    for (int i = 0; i < parser.Number; i++)
                    {
                        FVIL.GDI.CFviGdiLineSegment ls = new FVIL.GDI.CFviGdiLineSegment();
                        ls.St = parser.Radial.Center;
                        ls.Ed = new FVIL.Data.CFviPoint(ls.St.X + parser.Radial.Radius, ls.St.Y);
                        ls.Angle = new FVIL.Data.CFviAngle(360 / parser.Number * i);
                        ls.Pen.Color = System.Drawing.Color.FromArgb(255, 255, 0);
                        lines.Add(ls);
                    }

                    pOverlay0.Figures.Add(center);
                    pOverlay0.Figures.Add(circle);
                    for (int i = 0; i < lines.Count; i++)
                        pOverlay0.Figures.Add(lines[i]);
                }

                for (int i = 0; i < (parser.Result.Count); i++)
                {
                    FVIL.Edge.CFviEdgeData edge = parser.Result[i];

                    FVIL.GDI.CFviGdiPoint position = new FVIL.GDI.CFviGdiPoint(edge.Position);
                    position.Size = new System.Drawing.Size(3, 3);
                    position.Style = FVIL.GDI.FigureStyle.Cross;
                    position.Pen.Color = System.Drawing.Color.FromArgb(255, 0, 0);

                    pOverlay0.Figures.Add(position);
                }

                display.SaveImage(dst, display.DisplayRect, 1.0);
            }
            return dst;
        }

    }
}
